/*================================================================
*   Copyright (C) 2022 Sangfor Ltd. All rights reserved.
*   
*   文件名称：tools.hpp
*   创 建 者：wudu
*   创建日期：2022年03月30日
*   描    述：
*           1.提供一个字符串切分函数
*
================================================================*/

#pragma once
#include <sys/time.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <unordered_map>

#include <boost/algorithm/string.hpp>


using namespace std;

//1.提供一个字符串切分函数
class StringUtil{
    public:
        static void Spilt(const string& input, const string& split_char,  vector<string>* output){
            boost::split(*output, input, boost::is_any_of(split_char), boost::token_compress_off);
        }
};


class FileUtil{
    public:
        /*
         * filename : 文件名
         * content ： 读到的文件内容， 返回给调用者， 输出型参数
         * */
        static bool ReadFile(const string& filename, string* content){
            content->clear();

            ifstream file(filename.c_str());
            if(!file.is_open()){
                perror("ReadFile");
                return false;
            }

            string line;
            while(getline(file, line)){
                *content += line + "\n";
            }

            file.close();
            return true;
        }

        static bool WriteFile(const string& filename, const string& data){
            ofstream file(filename.c_str());
            if(!file.is_open()){
                return false;
            }

            printf("begin write file...\n");
            file.write(data.c_str(), data.size());
            file.close();
            return true;
        }
};


class UrlUtil{
    public:
        static void PraseBody(const string& body, unordered_map<string, string>* body_kv){
            vector<string> vec;
            StringUtil::Spilt(body, "&", &vec);

            for(const auto& k : vec){
                vector<string> v;
                StringUtil::Spilt(k, "=", &v);

                if(v.size() != 2){
                    continue;
                }
                //对于切分完成的value进行url的解码
                (*body_kv)[v[0]] = UrlDecode(v[1]);
            }
        }
        
        static unsigned char ToHex(unsigned char x) {   
            return  x > 9 ? x + 55 : x + 48;   
        }  
          
        static unsigned char FromHex(unsigned char x)   {   
            unsigned char y;  
            if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;  
            else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;  
            else if (x >= '0' && x <= '9') y = x - '0';  
            else assert(0);  
            return y;  
        }  
          
        static std::string UrlEncode(const std::string& str)  {  
            std::string strTemp = "";  
            size_t length = str.length();  
            for (size_t i = 0; i < length; i++)  {  
                if (isalnum((unsigned char)str[i]) ||   
                    (str[i] == '-') ||  
                    (str[i] == '_') ||   
                    (str[i] == '.') ||   
                    (str[i] == '~'))  
                    strTemp += str[i];  
                else if (str[i] == ' ')  
                    strTemp += "+";  
                else  {  
                    strTemp += '%';  
                    strTemp += ToHex((unsigned char)str[i] >> 4);  
                    strTemp += ToHex((unsigned char)str[i] % 16);  
                }  
            }  
            return strTemp;  
        }  
          
        static std::string UrlDecode(const std::string& str)  {  
            std::string strTemp = "";  
            size_t length = str.length();  
            for (size_t i = 0; i < length; i++)  {  
                if (str[i] == '+') strTemp += ' ';  
                else if (str[i] == '%')  {  
                    assert(i + 2 < length);  
                    unsigned char high = FromHex((unsigned char)str[++i]);  
                    unsigned char low = FromHex((unsigned char)str[++i]);  
                    strTemp += high*16 + low;  
                }  
                else strTemp += str[i];  
            }  
            return strTemp;  
        } 
};



class TimeUtil{
    public:
        static int64_t GetTimeStmapMs(){
            struct timeval tv;
            gettimeofday(&tv, NULL);
            return tv.tv_sec * 1000 + tv.tv_usec / 1000;
        }

        static string GetTimeStamp(){
            time_t st;
            time(&st);
            
            struct tm* t = localtime(&st);
            
            char buf[30] = {0};
            snprintf(buf, sizeof(buf) - 1, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
            string timestamp = buf;
            return timestamp;
        }
};


enum LogLevel{
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR,
    FATEL
};


// [日期-日志等级-file-line] 日志的具体内容
const char* Level[] = {
    "DEBUG",
    "INFO",
    "WARNING",
    "ERROR",
    "FATEL"
};


inline ostream& Log(LogLevel lev, const char* file, int line, const string& msg){
    string lev_info = Level[lev];
    string timestamp = TimeUtil::GetTimeStamp();


    cout << "[" << timestamp << "-" << lev_info << "-" << file << "-" << line << "]" << " " << msg;
    return cout;
}

#define LOG(lev, msg) Log(lev, __FILE__, __LINE__, msg)


